package com.shermanzhou.springbootflowable.demo;

import com.shermanzhou.springbootflowable.demo.custom.service.CustomCommentService;
import com.shermanzhou.springbootflowable.demo.flow.ApprovalFlow;
import com.shermanzhou.springbootflowable.demo.flow.ApprovalFlowNode;
import com.shermanzhou.springbootflowable.demo.utils.ModelConverter;
import org.assertj.core.util.Lists;
import org.flowable.bpmn.model.Process;
import org.flowable.bpmn.model.*;
import org.flowable.engine.ProcessEngine;
import org.flowable.engine.history.HistoricActivityInstance;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.repository.Deployment;
import org.flowable.task.api.TaskInfo;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author zhouchaoqun02
 * @date 2020-06-14 19:55
 */
@SpringBootTest
public class ApprovalFlowTest2 {

    private String jsonModel = "{\"modelId\":\"05fd4172-58bb-483c-9ac0-2edd91ec1e17\",\"bounds\":{\"lowerRight\":{\"x\":2560,\"y\":1050},\"upperLeft\":{\"x\":0,\"y\":0}},\"properties\":{\"process_id\":\"demo6\",\"name\":\"子流程套并行网关\"},\"childShapes\":[{\"resourceId\":\"sid-033a8cd6-8998-4078-b47c-46b55e4f4686\",\"properties\":{\"overrideid\":\"\",\"name\":\"StartEvent\"},\"stencil\":{\"id\":\"StartNoneEvent\"},\"childShapes\":[],\"outgoing\":[{\"resourceId\":\"sid-ECFD3131-D695-4A3B-860F-0B42859788A7\"}],\"bounds\":{\"lowerRight\":{\"x\":150,\"y\":325},\"upperLeft\":{\"x\":120,\"y\":295}},\"dockers\":[]},{\"resourceId\":\"sid-58756679-e60f-40cd-af05-81222e2a4845\",\"properties\":{\"overrideid\":\"\",\"name\":\"EndEvent\"},\"stencil\":{\"id\":\"EndNoneEvent\"},\"childShapes\":[],\"outgoing\":[],\"bounds\":{\"lowerRight\":{\"x\":1828,\"y\":357.5},\"upperLeft\":{\"x\":1800,\"y\":329.5}},\"dockers\":[]},{\"resourceId\":\"sid-E9A434DE-B254-4AAF-934F-4C4DB4392DAC\",\"properties\":{\"overrideid\":\"root1\",\"name\":\"root1\"},\"stencil\":{\"id\":\"UserTask\"},\"childShapes\":[],\"outgoing\":[{\"resourceId\":\"sid-D3EEBA3F-F653-4205-AE6C-76E953A3B8B9\"}],\"bounds\":{\"lowerRight\":{\"x\":340,\"y\":350},\"upperLeft\":{\"x\":240,\"y\":270}},\"dockers\":[]},{\"resourceId\":\"sid-E707FA5B-3838-4C87-A99C-1484145E9E93\",\"properties\":{\"overrideid\":\"ziliucheng\",\"name\":\"子流程\",\"executionlisteners\":\"\",\"multiinstance_type\":\"Parallel\",\"multiinstance_collection\":\"ids\",\"multiinstance_variable\":\"id\"},\"stencil\":{\"id\":\"SubProcess\"},\"childShapes\":[{\"resourceId\":\"sid-73CD9182-14A2-41DF-A48A-506ECC2DDE04\",\"properties\":{\"overrideid\":\"zifenzhi1\",\"name\":\"子分支1\"},\"stencil\":{\"id\":\"UserTask\"},\"childShapes\":[],\"outgoing\":[{\"resourceId\":\"sid-91E83A9E-8426-4B1B-B834-BE0A906C4974\"}],\"bounds\":{\"lowerRight\":{\"x\":310,\"y\":110},\"upperLeft\":{\"x\":210,\"y\":30}},\"dockers\":[]},{\"resourceId\":\"sid-2F6D1D2F-D558-4800-A6F4-EE7E35CFA1AA\",\"properties\":{\"overrideid\":\"\",\"name\":\"\"},\"stencil\":{\"id\":\"StartNoneEvent\"},\"childShapes\":[],\"outgoing\":[{\"resourceId\":\"sid-DE5CB1E7-0FC9-407D-B114-7098B4C56CFD\"}],\"bounds\":{\"lowerRight\":{\"x\":60,\"y\":225},\"upperLeft\":{\"x\":30,\"y\":195}},\"dockers\":[]},{\"resourceId\":\"sid-38B3F6E5-C2DE-4A7B-A162-F8AD036FED76\",\"properties\":{\"overrideid\":\"zifengzhi2\",\"name\":\"子分支2\"},\"stencil\":{\"id\":\"UserTask\"},\"childShapes\":[],\"outgoing\":[{\"resourceId\":\"sid-403F7A2D-B19E-44B2-BD8E-95C65783BAE7\"}],\"bounds\":{\"lowerRight\":{\"x\":310,\"y\":243.5},\"upperLeft\":{\"x\":210,\"y\":163.5}},\"dockers\":[]},{\"resourceId\":\"sid-9F278D88-7002-49E8-8963-FDA57ACAED12\",\"properties\":{\"overrideid\":\"zifengzhi3\",\"name\":\"子分支3\"},\"stencil\":{\"id\":\"UserTask\"},\"childShapes\":[],\"outgoing\":[{\"resourceId\":\"sid-BF38C521-B579-40F0-AE91-765090DE09D8\"}],\"bounds\":{\"lowerRight\":{\"x\":310,\"y\":365},\"upperLeft\":{\"x\":210,\"y\":285}},\"dockers\":[]},{\"resourceId\":\"sid-88BB65E4-7D51-4FCA-A3F2-75F7AD6C3015\",\"properties\":{\"overrideid\":\"zibingxing1\",\"name\":\"zibingxing1\",\"sequencefloworder\":\"\"},\"stencil\":{\"id\":\"ParallelGateway\"},\"childShapes\":[],\"outgoing\":[{\"resourceId\":\"sid-9BD551E6-9F34-48B8-8938-45CBCD5CFC7F\"},{\"resourceId\":\"sid-4A3960A7-AA57-48E3-829D-6C4C7869A967\"},{\"resourceId\":\"sid-D3AB3896-421B-4106-BCBE-F988556EB63E\"}],\"bounds\":{\"lowerRight\":{\"x\":145,\"y\":220},\"upperLeft\":{\"x\":105,\"y\":180}},\"dockers\":[]},{\"resourceId\":\"sid-4D6AD65B-3CE8-4A0F-8B79-979953E3D12E\",\"properties\":{\"overrideid\":\"zibingxing2\",\"name\":\"zibingxing2\",\"sequencefloworder\":\"\"},\"stencil\":{\"id\":\"ParallelGateway\"},\"childShapes\":[],\"outgoing\":[{\"resourceId\":\"sid-77795D5E-4487-4411-8B1B-537DAC73BB99\"}],\"bounds\":{\"lowerRight\":{\"x\":385,\"y\":220},\"upperLeft\":{\"x\":345,\"y\":180}},\"dockers\":[]},{\"resourceId\":\"sid-05A91F00-9792-41E0-9D34-461C4E61DDA3\",\"properties\":{\"overrideid\":\"ziroot\",\"name\":\"ziroot\"},\"stencil\":{\"id\":\"UserTask\"},\"childShapes\":[],\"outgoing\":[{\"resourceId\":\"sid-3B2DAA5C-DD01-4397-836D-A67AD5AE1E29\"}],\"bounds\":{\"lowerRight\":{\"x\":535,\"y\":230},\"upperLeft\":{\"x\":435,\"y\":150}},\"dockers\":[]},{\"resourceId\":\"sid-D459B46A-FE20-4F04-AFBE-CBFBA7D3166F\",\"properties\":{\"overrideid\":\"\",\"name\":\"\"},\"stencil\":{\"id\":\"EndNoneEvent\"},\"childShapes\":[],\"outgoing\":[],\"bounds\":{\"lowerRight\":{\"x\":608,\"y\":217.5},\"upperLeft\":{\"x\":580,\"y\":189.5}},\"dockers\":[]}],\"outgoing\":[{\"resourceId\":\"sid-2152C036-4411-416F-8229-D31362C21E35\"}],\"bounds\":{\"lowerRight\":{\"x\":1184,\"y\":552},\"upperLeft\":{\"x\":420,\"y\":135}},\"dockers\":[]},{\"resourceId\":\"sid-D3EEBA3F-F653-4205-AE6C-76E953A3B8B9\",\"properties\":{\"overrideid\":\"\",\"name\":\"\",\"conditionsequenceflow\":\"\",\"defaultflow\":\"false\"},\"stencil\":{\"id\":\"SequenceFlow\"},\"childShapes\":[],\"outgoing\":[{\"resourceId\":\"sid-E707FA5B-3838-4C87-A99C-1484145E9E93\"}],\"bounds\":{\"lowerRight\":{\"x\":419.4375,\"y\":343.5},\"upperLeft\":{\"x\":340.21875,\"y\":310}},\"dockers\":[{\"x\":50,\"y\":40},{\"x\":395,\"y\":310},{\"x\":395,\"y\":343.5},{\"x\":382,\"y\":208.50000000000003}],\"target\":{\"resourceId\":\"sid-E707FA5B-3838-4C87-A99C-1484145E9E93\"}},{\"resourceId\":\"sid-ECFD3131-D695-4A3B-860F-0B42859788A7\",\"properties\":{\"overrideid\":\"\",\"name\":\"\",\"conditionsequenceflow\":\"\",\"defaultflow\":\"false\"},\"stencil\":{\"id\":\"SequenceFlow\"},\"childShapes\":[],\"outgoing\":[{\"resourceId\":\"sid-E9A434DE-B254-4AAF-934F-4C4DB4392DAC\"}],\"bounds\":{\"lowerRight\":{\"x\":239.3515625,\"y\":310},\"upperLeft\":{\"x\":150.53125,\"y\":310}},\"dockers\":[{\"x\":15,\"y\":15},{\"x\":50,\"y\":40}],\"target\":{\"resourceId\":\"sid-E9A434DE-B254-4AAF-934F-4C4DB4392DAC\"}},{\"resourceId\":\"sid-DE5CB1E7-0FC9-407D-B114-7098B4C56CFD\",\"properties\":{\"overrideid\":\"\",\"name\":\"\",\"conditionsequenceflow\":\"\",\"defaultflow\":\"false\"},\"stencil\":{\"id\":\"SequenceFlow\"},\"childShapes\":[],\"outgoing\":[{\"resourceId\":\"sid-88BB65E4-7D51-4FCA-A3F2-75F7AD6C3015\"}],\"bounds\":{\"lowerRight\":{\"x\":524.34375,\"y\":345},\"upperLeft\":{\"x\":480.0625,\"y\":335.5}},\"dockers\":[{\"x\":15,\"y\":15},{\"x\":502.5,\"y\":345},{\"x\":502.5,\"y\":335.5},{\"x\":20.5,\"y\":20.5}],\"target\":{\"resourceId\":\"sid-88BB65E4-7D51-4FCA-A3F2-75F7AD6C3015\"}},{\"resourceId\":\"sid-9BD551E6-9F34-48B8-8938-45CBCD5CFC7F\",\"properties\":{\"overrideid\":\"\",\"name\":\"\",\"conditionsequenceflow\":\"\",\"defaultflow\":\"false\"},\"stencil\":{\"id\":\"SequenceFlow\"},\"childShapes\":[],\"outgoing\":[{\"resourceId\":\"sid-73CD9182-14A2-41DF-A48A-506ECC2DDE04\"}],\"bounds\":{\"lowerRight\":{\"x\":638.3018329141196,\"y\":325.62786460254733},\"upperLeft\":{\"x\":555.6747295858804,\"y\":245.4580728974527}},\"dockers\":[{\"x\":20.5,\"y\":20.5},{\"x\":50,\"y\":40}],\"target\":{\"resourceId\":\"sid-73CD9182-14A2-41DF-A48A-506ECC2DDE04\"}},{\"resourceId\":\"sid-4A3960A7-AA57-48E3-829D-6C4C7869A967\",\"properties\":{\"overrideid\":\"\",\"name\":\"\",\"conditionsequenceflow\":\"\",\"defaultflow\":\"false\"},\"stencil\":{\"id\":\"SequenceFlow\"},\"childShapes\":[],\"outgoing\":[{\"resourceId\":\"sid-38B3F6E5-C2DE-4A7B-A162-F8AD036FED76\"}],\"bounds\":{\"lowerRight\":{\"x\":629.6135299100027,\"y\":337.376138213606},\"upperLeft\":{\"x\":565.4138138399973,\"y\":335.944174286394}},\"dockers\":[{\"x\":20.5,\"y\":20.5},{\"x\":50,\"y\":40}],\"target\":{\"resourceId\":\"sid-38B3F6E5-C2DE-4A7B-A162-F8AD036FED76\"}},{\"resourceId\":\"sid-D3AB3896-421B-4106-BCBE-F988556EB63E\",\"properties\":{\"overrideid\":\"\",\"name\":\"\",\"conditionsequenceflow\":\"\",\"defaultflow\":\"false\"},\"stencil\":{\"id\":\"SequenceFlow\"},\"childShapes\":[],\"outgoing\":[{\"resourceId\":\"sid-9F278D88-7002-49E8-8963-FDA57ACAED12\"}],\"bounds\":{\"lowerRight\":{\"x\":636.1841073414588,\"y\":419.4417945279675},\"upperLeft\":{\"x\":555.6908926585412,\"y\":344.9332054720325}},\"dockers\":[{\"x\":20.5,\"y\":20.5},{\"x\":50,\"y\":40}],\"target\":{\"resourceId\":\"sid-9F278D88-7002-49E8-8963-FDA57ACAED12\"}},{\"resourceId\":\"sid-403F7A2D-B19E-44B2-BD8E-95C65783BAE7\",\"properties\":{\"overrideid\":\"\",\"name\":\"\",\"conditionsequenceflow\":\"\",\"defaultflow\":\"false\"},\"stencil\":{\"id\":\"SequenceFlow\"},\"childShapes\":[],\"outgoing\":[{\"resourceId\":\"sid-4D6AD65B-3CE8-4A0F-8B79-979953E3D12E\"}],\"bounds\":{\"lowerRight\":{\"x\":764.7191540585601,\"y\":337.06532547085953},\"upperLeft\":{\"x\":730.4527209414399,\"y\":336.09092452914047}},\"dockers\":[{\"x\":50,\"y\":40},{\"x\":20.5,\"y\":20.5}],\"target\":{\"resourceId\":\"sid-4D6AD65B-3CE8-4A0F-8B79-979953E3D12E\"}},{\"resourceId\":\"sid-91E83A9E-8426-4B1B-B834-BE0A906C4974\",\"properties\":{\"overrideid\":\"\",\"name\":\"\",\"conditionsequenceflow\":\"\",\"defaultflow\":\"false\"},\"stencil\":{\"id\":\"SequenceFlow\"},\"childShapes\":[],\"outgoing\":[{\"resourceId\":\"sid-4D6AD65B-3CE8-4A0F-8B79-979953E3D12E\"}],\"bounds\":{\"lowerRight\":{\"x\":776.1685378929124,\"y\":324.0658088197963},\"upperLeft\":{\"x\":712.6205246070876,\"y\":245.38731618020375}},\"dockers\":[{\"x\":50,\"y\":40},{\"x\":20,\"y\":20}],\"target\":{\"resourceId\":\"sid-4D6AD65B-3CE8-4A0F-8B79-979953E3D12E\"}},{\"resourceId\":\"sid-BF38C521-B579-40F0-AE91-765090DE09D8\",\"properties\":{\"overrideid\":\"\",\"name\":\"\",\"conditionsequenceflow\":\"\",\"defaultflow\":\"false\"},\"stencil\":{\"id\":\"SequenceFlow\"},\"childShapes\":[],\"outgoing\":[{\"resourceId\":\"sid-4D6AD65B-3CE8-4A0F-8B79-979953E3D12E\"}],\"bounds\":{\"lowerRight\":{\"x\":775.3333704135767,\"y\":419.6835138852104},\"upperLeft\":{\"x\":713.8658483364233,\"y\":346.5078923647896}},\"dockers\":[{\"x\":50,\"y\":40},{\"x\":20,\"y\":20}],\"target\":{\"resourceId\":\"sid-4D6AD65B-3CE8-4A0F-8B79-979953E3D12E\"}},{\"resourceId\":\"sid-77795D5E-4487-4411-8B1B-537DAC73BB99\",\"properties\":{\"overrideid\":\"\",\"name\":\"\",\"conditionsequenceflow\":\"\",\"defaultflow\":\"false\"},\"stencil\":{\"id\":\"SequenceFlow\"},\"childShapes\":[],\"outgoing\":[{\"resourceId\":\"sid-05A91F00-9792-41E0-9D34-461C4E61DDA3\"}],\"bounds\":{\"lowerRight\":{\"x\":854.78125,\"y\":335.5},\"upperLeft\":{\"x\":805.96875,\"y\":325}},\"dockers\":[{\"x\":20.5,\"y\":20.5},{\"x\":830,\"y\":335.5},{\"x\":830,\"y\":325},{\"x\":50,\"y\":40}],\"target\":{\"resourceId\":\"sid-05A91F00-9792-41E0-9D34-461C4E61DDA3\"}},{\"resourceId\":\"sid-927A3964-F444-4361-B4FE-58AF7136F38A\",\"properties\":{\"overrideid\":\"root2\",\"name\":\"root2\"},\"stencil\":{\"id\":\"UserTask\"},\"childShapes\":[],\"outgoing\":[{\"resourceId\":\"sid-DF6F0C4F-A2AB-4F16-A7C0-B879A6A84083\"}],\"bounds\":{\"lowerRight\":{\"x\":1315,\"y\":380},\"upperLeft\":{\"x\":1215,\"y\":300}},\"dockers\":[]},{\"resourceId\":\"sid-2152C036-4411-416F-8229-D31362C21E35\",\"properties\":{\"overrideid\":\"\",\"name\":\"\",\"conditionsequenceflow\":\"\",\"defaultflow\":\"false\"},\"stencil\":{\"id\":\"SequenceFlow\"},\"childShapes\":[],\"outgoing\":[{\"resourceId\":\"sid-927A3964-F444-4361-B4FE-58AF7136F38A\"}],\"bounds\":{\"lowerRight\":{\"x\":1214.2637004460037,\"y\":340.60767519573113},\"upperLeft\":{\"x\":1184.6132526789963,\"y\":340.38353574176887}},\"dockers\":[{\"x\":382,\"y\":208.50000000000003},{\"x\":50,\"y\":40}],\"target\":{\"resourceId\":\"sid-927A3964-F444-4361-B4FE-58AF7136F38A\"}},{\"resourceId\":\"sid-5FA5DB66-581F-4708-9930-33678638EF9B\",\"properties\":{\"overrideid\":\"bingxingwangguan2\",\"name\":\"并行网关2\",\"sequencefloworder\":\"\"},\"stencil\":{\"id\":\"ParallelGateway\"},\"childShapes\":[],\"outgoing\":[{\"resourceId\":\"sid-6259DA04-D981-4607-B5E2-83D47EFDD1F3\"},{\"resourceId\":\"sid-2900871A-D6DE-4A43-A265-2DCF801E0E29\"},{\"resourceId\":\"sid-D11AABFD-D6FD-45CF-91AD-F8859DA25220\"}],\"bounds\":{\"lowerRight\":{\"x\":1390,\"y\":355},\"upperLeft\":{\"x\":1350,\"y\":315}},\"dockers\":[]},{\"resourceId\":\"sid-DF6F0C4F-A2AB-4F16-A7C0-B879A6A84083\",\"properties\":{\"overrideid\":\"\",\"name\":\"\",\"conditionsequenceflow\":\"\",\"defaultflow\":\"false\"},\"stencil\":{\"id\":\"SequenceFlow\"},\"childShapes\":[],\"outgoing\":[{\"resourceId\":\"sid-5FA5DB66-581F-4708-9930-33678638EF9B\"}],\"bounds\":{\"lowerRight\":{\"x\":1350.543877193665,\"y\":337.8480097203459},\"upperLeft\":{\"x\":1315.452216556335,\"y\":336.3512090296541}},\"dockers\":[{\"x\":50,\"y\":40},{\"x\":20.5,\"y\":20.5}],\"target\":{\"resourceId\":\"sid-5FA5DB66-581F-4708-9930-33678638EF9B\"}},{\"resourceId\":\"sid-417435FD-6EFC-4CDC-9CE5-7055A1EDF54B\",\"properties\":{\"overrideid\":\"bingxingfenzhi2\",\"name\":\"并行分支2\"},\"stencil\":{\"id\":\"UserTask\"},\"childShapes\":[],\"outgoing\":[{\"resourceId\":\"sid-FD44CD95-61DB-44A5-9BB2-5BA88CAD6738\"}],\"bounds\":{\"lowerRight\":{\"x\":1540,\"y\":380},\"upperLeft\":{\"x\":1440,\"y\":300}},\"dockers\":[]},{\"resourceId\":\"sid-6259DA04-D981-4607-B5E2-83D47EFDD1F3\",\"properties\":{\"overrideid\":\"\",\"name\":\"\",\"conditionsequenceflow\":\"\",\"defaultflow\":\"false\"},\"stencil\":{\"id\":\"SequenceFlow\"},\"childShapes\":[],\"outgoing\":[{\"resourceId\":\"sid-417435FD-6EFC-4CDC-9CE5-7055A1EDF54B\"}],\"bounds\":{\"lowerRight\":{\"x\":1439.78125,\"y\":340},\"upperLeft\":{\"x\":1390.96875,\"y\":335.5}},\"dockers\":[{\"x\":20.5,\"y\":20.5},{\"x\":1415,\"y\":335.5},{\"x\":1415,\"y\":340},{\"x\":50,\"y\":40}],\"target\":{\"resourceId\":\"sid-417435FD-6EFC-4CDC-9CE5-7055A1EDF54B\"}},{\"resourceId\":\"sid-6602CCFB-1CFF-4C18-B4FE-C6D31A9769A7\",\"properties\":{\"overrideid\":\"bingxingfenzhi3\",\"name\":\"并行分支3\"},\"stencil\":{\"id\":\"UserTask\"},\"childShapes\":[],\"outgoing\":[{\"resourceId\":\"sid-8C897878-0A1C-4E9A-BAA6-3D80F62176C9\"}],\"bounds\":{\"lowerRight\":{\"x\":1540,\"y\":500},\"upperLeft\":{\"x\":1440,\"y\":420}},\"dockers\":[]},{\"resourceId\":\"sid-2900871A-D6DE-4A43-A265-2DCF801E0E29\",\"properties\":{\"overrideid\":\"\",\"name\":\"\",\"conditionsequenceflow\":\"\",\"defaultflow\":\"false\"},\"stencil\":{\"id\":\"SequenceFlow\"},\"childShapes\":[],\"outgoing\":[{\"resourceId\":\"sid-6602CCFB-1CFF-4C18-B4FE-C6D31A9769A7\"}],\"bounds\":{\"lowerRight\":{\"x\":1490,\"y\":419.625},\"upperLeft\":{\"x\":1370.5,\"y\":355.234375}},\"dockers\":[{\"x\":20.5,\"y\":20.5},{\"x\":1370.5,\"y\":390},{\"x\":1490,\"y\":390},{\"x\":50,\"y\":40}],\"target\":{\"resourceId\":\"sid-6602CCFB-1CFF-4C18-B4FE-C6D31A9769A7\"}},{\"resourceId\":\"sid-E8565DB3-FC8F-435B-97AE-8F5CFACBC68B\",\"properties\":{\"overrideid\":\"bingxingfenzhi1\",\"name\":\"并行分支1\"},\"stencil\":{\"id\":\"UserTask\"},\"childShapes\":[],\"outgoing\":[{\"resourceId\":\"sid-8E6C5B4A-9FB2-4A29-A6B9-5C4065AE847D\"}],\"bounds\":{\"lowerRight\":{\"x\":1540,\"y\":260},\"upperLeft\":{\"x\":1440,\"y\":180}},\"dockers\":[]},{\"resourceId\":\"sid-D11AABFD-D6FD-45CF-91AD-F8859DA25220\",\"properties\":{\"overrideid\":\"\",\"name\":\"\",\"conditionsequenceflow\":\"\",\"defaultflow\":\"false\"},\"stencil\":{\"id\":\"SequenceFlow\"},\"childShapes\":[],\"outgoing\":[{\"resourceId\":\"sid-E8565DB3-FC8F-435B-97AE-8F5CFACBC68B\"}],\"bounds\":{\"lowerRight\":{\"x\":1490,\"y\":314.59375},\"upperLeft\":{\"x\":1370.5,\"y\":260.375}},\"dockers\":[{\"x\":20.5,\"y\":20.5},{\"x\":1370.5,\"y\":290},{\"x\":1490,\"y\":290},{\"x\":50,\"y\":40}],\"target\":{\"resourceId\":\"sid-E8565DB3-FC8F-435B-97AE-8F5CFACBC68B\"}},{\"resourceId\":\"sid-27579F5E-F4A1-4675-AB3B-4DA4A1214482\",\"properties\":{\"overrideid\":\"bingxingwangguan3\",\"name\":\"并行网关3\",\"sequencefloworder\":\"\"},\"stencil\":{\"id\":\"ParallelGateway\"},\"childShapes\":[],\"outgoing\":[{\"resourceId\":\"sid-97138BC0-B1F2-49FB-B089-93ED13CE75D2\"}],\"bounds\":{\"lowerRight\":{\"x\":1660,\"y\":355},\"upperLeft\":{\"x\":1620,\"y\":315}},\"dockers\":[]},{\"resourceId\":\"sid-FD44CD95-61DB-44A5-9BB2-5BA88CAD6738\",\"properties\":{\"overrideid\":\"\",\"name\":\"\",\"conditionsequenceflow\":\"\",\"defaultflow\":\"false\"},\"stencil\":{\"id\":\"SequenceFlow\"},\"childShapes\":[],\"outgoing\":[{\"resourceId\":\"sid-27579F5E-F4A1-4675-AB3B-4DA4A1214482\"}],\"bounds\":{\"lowerRight\":{\"x\":1620.25,\"y\":340},\"upperLeft\":{\"x\":1540.21875,\"y\":335}},\"dockers\":[{\"x\":50,\"y\":40},{\"x\":1580,\"y\":340},{\"x\":1580,\"y\":335},{\"x\":20,\"y\":20}],\"target\":{\"resourceId\":\"sid-27579F5E-F4A1-4675-AB3B-4DA4A1214482\"}},{\"resourceId\":\"sid-8C897878-0A1C-4E9A-BAA6-3D80F62176C9\",\"properties\":{\"overrideid\":\"\",\"name\":\"\",\"conditionsequenceflow\":\"\",\"defaultflow\":\"false\"},\"stencil\":{\"id\":\"SequenceFlow\"},\"childShapes\":[],\"outgoing\":[{\"resourceId\":\"sid-27579F5E-F4A1-4675-AB3B-4DA4A1214482\"}],\"bounds\":{\"lowerRight\":{\"x\":1628.6849037204026,\"y\":419.80903435033554},\"upperLeft\":{\"x\":1538.2291587795974,\"y\":344.42924689966446}},\"dockers\":[{\"x\":50,\"y\":40},{\"x\":20,\"y\":20}],\"target\":{\"resourceId\":\"sid-27579F5E-F4A1-4675-AB3B-4DA4A1214482\"}},{\"resourceId\":\"sid-8E6C5B4A-9FB2-4A29-A6B9-5C4065AE847D\",\"properties\":{\"overrideid\":\"\",\"name\":\"\",\"conditionsequenceflow\":\"\",\"defaultflow\":\"false\"},\"stencil\":{\"id\":\"SequenceFlow\"},\"childShapes\":[],\"outgoing\":[{\"resourceId\":\"sid-27579F5E-F4A1-4675-AB3B-4DA4A1214482\"}],\"bounds\":{\"lowerRight\":{\"x\":1640.5,\"y\":314.6484375},\"upperLeft\":{\"x\":1540.3828125,\"y\":220}},\"dockers\":[{\"x\":50,\"y\":40},{\"x\":1640.5,\"y\":220},{\"x\":20.5,\"y\":20.5}],\"target\":{\"resourceId\":\"sid-27579F5E-F4A1-4675-AB3B-4DA4A1214482\"}},{\"resourceId\":\"sid-97138BC0-B1F2-49FB-B089-93ED13CE75D2\",\"properties\":{\"overrideid\":\"\",\"name\":\"\",\"conditionsequenceflow\":\"\",\"defaultflow\":\"false\",\"showdiamondmarker\":false},\"stencil\":{\"id\":\"SequenceFlow\"},\"childShapes\":[],\"outgoing\":[{\"resourceId\":\"sid-58756679-e60f-40cd-af05-81222e2a4845\"}],\"bounds\":{\"lowerRight\":{\"x\":1799.3125,\"y\":337.5},\"upperLeft\":{\"x\":1660.27734375,\"y\":335.5}},\"dockers\":[{\"x\":20.5,\"y\":20.5},{\"x\":1745,\"y\":335.5},{\"x\":1745,\"y\":337.5},{\"x\":5,\"y\":8}],\"target\":{\"resourceId\":\"sid-58756679-e60f-40cd-af05-81222e2a4845\"}},{\"resourceId\":\"sid-3B2DAA5C-DD01-4397-836D-A67AD5AE1E29\",\"properties\":{\"overrideid\":\"\",\"name\":\"\",\"conditionsequenceflow\":\"\",\"defaultflow\":\"false\"},\"stencil\":{\"id\":\"SequenceFlow\"},\"childShapes\":[],\"outgoing\":[{\"resourceId\":\"sid-D459B46A-FE20-4F04-AFBE-CBFBA7D3166F\"}],\"bounds\":{\"lowerRight\":{\"x\":999.3825826830113,\"y\":336.6895859286298},\"upperLeft\":{\"x\":955.3830423169887,\"y\":331.2401015713702}},\"dockers\":[{\"x\":50,\"y\":40},{\"x\":14,\"y\":14}],\"target\":{\"resourceId\":\"sid-D459B46A-FE20-4F04-AFBE-CBFBA7D3166F\"}}],\"stencil\":{\"id\":\"BPMNDiagram\"},\"stencilset\":{\"namespace\":\"http://b3mn.org/stencilset/bpmn2.0#\",\"url\":\"../editor/stencilsets/bpmn2.0/bpmn2.0.json\"}}";

    @Autowired
    @Qualifier("normalProcessEngine")
    private ProcessEngine normalEngine;

    @Autowired
    @Qualifier("simulateProcessEngine")
    private ProcessEngine simulateEngine;

    @Autowired
    private CustomCommentService customCommentService;


    @Test
    public void deploy() {
        BpmnModel bpmnModel = ModelConverter.jsonToBpmnModel(jsonModel);
        Deployment deploy = normalEngine.getRepositoryService().createDeployment()
                .addBpmnModel("bpmnModel.bpmn", bpmnModel)
                .name("子流程套并行网关")
                .key("demo6")
                .deploy();
        System.out.println(deploy.getId());
    }

    public String deploySimulate() {
        BpmnModel bpmnModel = ModelConverter.jsonToBpmnModel(jsonModel);
        Deployment deploy = simulateEngine.getRepositoryService().createDeployment()
                .addBpmnModel("bpmnModel.bpmn", bpmnModel)
                .name("子流程套并行网关")
                .key("demo6")
                .deploy();
        System.out.println(deploy.getId());
        return deploy.getId();
    }

    @Test
    public void finishedProcInstFlow() {
        String procInstId = "7501";
        HistoricProcessInstance historicProcessInstance = normalEngine.getHistoryService().createHistoricProcessInstanceQuery().processInstanceId(procInstId).singleResult();

        List<HistoricTaskInstance> hisTasks = normalEngine.getHistoryService().createHistoricTaskInstanceQuery().includeTaskLocalVariables().processInstanceId(procInstId).list();
        Map<String, List<TaskInfo>> actIdAndHisTasksMap = hisTasks.stream().collect(Collectors.groupingBy(TaskInfo::getTaskDefinitionKey));


        List<String> actTypes = Lists.newArrayList("startEvent", "subProcess", "userTask");
        List<HistoricActivityInstance> actHistoryList = normalEngine.getHistoryService().createHistoricActivityInstanceQuery().processInstanceId(procInstId).list();
        Map<String, List<HistoricActivityInstance>> actIdAndActivitiesMap = actHistoryList.stream().filter(act -> actTypes.contains(act.getActivityType())).collect(Collectors.groupingBy(act -> act.getActivityId()));

        Process process = normalEngine.getRepositoryService().getBpmnModel(historicProcessInstance.getProcessDefinitionId()).getProcesses().get(0);

        ApprovalFlow approvalFlow = makeUpRootApprovalFlow(process, actIdAndActivitiesMap, actIdAndHisTasksMap);

        System.out.println(approvalFlow);
    }

    private ApprovalFlow makeUpRootApprovalFlow(Process process,
                                                Map<String, List<HistoricActivityInstance>> actIdAndActivitiesMap,
                                                Map<String, List<TaskInfo>> actIdAndHisTasksMap) {
        FlowNode startNode = (FlowNode) process.getInitialFlowElement();
        HistoricActivityInstance startAct = actIdAndActivitiesMap.get(startNode.getId()).get(0);
        ApprovalFlowNode root = ApprovalFlowNode.builder()
                .nodeId(startAct.getActivityId())
                .nodeName(startAct.getActivityName())
                .build();
        findAndCompleteTaskForNode(startAct, root, actIdAndHisTasksMap);
        makeUpSubProcessAndNextNodes(startAct, root, actIdAndActivitiesMap, process.getFlowElementMap(), actIdAndHisTasksMap, false);
        return ApprovalFlow.builder().approvalFlowNode(root).flowType(ApprovalFlow.ApprovalFlowTypeEnum.ROOT).build();
    }

    private List<ApprovalFlow> makeUpSubApprovalFlow(SubProcess subProcess,
                                                     Map<String, List<HistoricActivityInstance>> actIdAndActivitiesMap,
                                                     Map<String, List<TaskInfo>> actIdAndHisTasksMap) {
        MultiInstanceLoopCharacteristics loopCharacteristics = subProcess.getLoopCharacteristics();
        boolean isMultiInstance = loopCharacteristics != null;

        List<ApprovalFlow> subFlows = new ArrayList<>();

        FlowNode startNode = (FlowNode) subProcess.getFlowElements().stream()
                .filter(flowElement -> flowElement instanceof StartEvent)
                .findFirst().orElseThrow(() -> new RuntimeException("subProcess start event not found"));
        List<HistoricActivityInstance> startActivities = actIdAndActivitiesMap.get(startNode.getId());
        for (HistoricActivityInstance startAct : startActivities) {
            ApprovalFlowNode root = ApprovalFlowNode.builder()
                    .nodeId(startAct.getActivityId())
                    .nodeName(startAct.getActivityName())
                    .build();
            findAndCompleteTaskForNode(startAct, root, actIdAndHisTasksMap);
            makeUpSubProcessAndNextNodes(startAct, root, actIdAndActivitiesMap, subProcess.getFlowElementMap(), actIdAndHisTasksMap, isMultiInstance);
            ApprovalFlow subFlow = ApprovalFlow.builder().approvalFlowNode(root).flowType(ApprovalFlow.ApprovalFlowTypeEnum.SUB).build();
            subFlows.add(subFlow);
        }

        return subFlows;
    }

    private void makeUpSubProcessAndNextNodes(HistoricActivityInstance curActivity,
                                              ApprovalFlowNode curNode,
                                              Map<String, List<HistoricActivityInstance>> actIdAndActivitiesMap,
                                              Map<String, FlowElement> flowElementMap,
                                              Map<String, List<TaskInfo>> actIdAndHisTasksMap,
                                              boolean curActIsMultiInstance) {
        FlowNode curFlowNode = (FlowNode) flowElementMap.get(curActivity.getActivityId());
        if (curFlowNode instanceof SubProcess) {
            List<ApprovalFlow> subFLows = makeUpSubApprovalFlow((SubProcess)curFlowNode, actIdAndActivitiesMap, actIdAndHisTasksMap);
            curNode.setSubFlows(subFLows);
        }
        makeUpNextNodes(curActivity, curNode, actIdAndActivitiesMap, flowElementMap, actIdAndHisTasksMap, curActIsMultiInstance);
    }

    private void makeUpNextNodes(HistoricActivityInstance curActivity,
                                 ApprovalFlowNode curNode,
                                 Map<String, List<HistoricActivityInstance>> actIdAndActivitiesMap,
                                 Map<String, FlowElement> flowElementMap,
                                 Map<String, List<TaskInfo>> actIdAndHisTasksMap,
                                 boolean curActIsMultiInstance) {
        List<HistoricActivityInstance> nextActivities = getNextActivities(curActivity, actIdAndActivitiesMap, flowElementMap, curActIsMultiInstance);
        List<ApprovalFlowNode> nextNodes = new ArrayList<>();
        for (HistoricActivityInstance nextAct : nextActivities) {
            if (nextAct.getActivityType().toLowerCase().endsWith("gateway")) {
                List<HistoricActivityInstance> nextActsOfGateway = getNextActivities(curActivity, actIdAndActivitiesMap, flowElementMap, curActIsMultiInstance);
                for (HistoricActivityInstance nextActOfGateway : nextActsOfGateway) {
                    ApprovalFlowNode nextNodeOfGateway = ApprovalFlowNode.builder()
                            .nodeId(nextAct.getActivityId())
                            .nodeName(nextAct.getActivityName())
                            .build();
                    makeUpSubProcessAndNextNodes(nextActOfGateway, nextNodeOfGateway, actIdAndActivitiesMap, flowElementMap, actIdAndHisTasksMap, curActIsMultiInstance);
                    nextNodes.add(nextNodeOfGateway);
                }
            } else {
                ApprovalFlowNode nextNode = ApprovalFlowNode.builder()
                        .nodeId(nextAct.getActivityId())
                        .nodeName(nextAct.getActivityName())
                        .build();
                findAndCompleteTaskForNode(nextAct, nextNode, actIdAndHisTasksMap);
                makeUpSubProcessAndNextNodes(nextAct, nextNode, actIdAndActivitiesMap, flowElementMap, actIdAndHisTasksMap, curActIsMultiInstance);
                nextNodes.add(nextNode);
            }
        }
        curNode.setNextNodes(nextNodes);
    }

    private void findAndCompleteTaskForNode(HistoricActivityInstance activity, ApprovalFlowNode node, Map<String, List<TaskInfo>> actIdAndHisTasksMap) {
        List<TaskInfo> taskInfos = actIdAndHisTasksMap.get(activity.getId());
        if (taskInfos == null || taskInfos.size() == 0) {
            return;
        }
        taskInfos = taskInfos.stream().filter(task -> task.getExecutionId().equals(activity.getExecutionId())).collect(Collectors.toList());
        node.setTaskEntities(taskInfos);
    }

    private List<HistoricActivityInstance> getNextActivities(HistoricActivityInstance curActivity,
                                                             Map<String, List<HistoricActivityInstance>> actIdAndActivitiesMap,
                                                             Map<String, FlowElement> flowElementMap,
                                                             boolean multiInstance) {
        List<HistoricActivityInstance> ret = new ArrayList<>();

        FlowNode curNode = (FlowNode) flowElementMap.get(curActivity.getActivityId());
        List<SequenceFlow> outgoingFlows = curNode.getOutgoingFlows();
        if (outgoingFlows == null || outgoingFlows.size() == 0) {
            throw new RuntimeException("next flow not found, current flowElement id: " + curNode.getId());
        }

        for (SequenceFlow outgoingFlow : outgoingFlows) {
            FlowElement targetFlowElement = outgoingFlow.getTargetFlowElement();
            List<HistoricActivityInstance> nextActs = actIdAndActivitiesMap.get(targetFlowElement.getId());
            if (nextActs == null || nextActs.size() == 0) {
                continue;
            }
            if (multiInstance) {
                nextActs = nextActs.stream().filter(act -> act.getExecutionId().equals(curActivity.getExecutionId())).collect(Collectors.toList());
            }
            ret.addAll(nextActs);
        }

        return ret;
    }

}
